001    /*
002     *  Copyright 2001-2005 Stephen Colebourne
003     *
004     *  Licensed under the Apache License, Version 2.0 (the "License");
005     *  you may not use this file except in compliance with the License.
006     *  You may obtain a copy of the License at
007     *
008     *      http://www.apache.org/licenses/LICENSE-2.0
009     *
010     *  Unless required by applicable law or agreed to in writing, software
011     *  distributed under the License is distributed on an "AS IS" BASIS,
012     *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     *  See the License for the specific language governing permissions and
014     *  limitations under the License.
015     */
016    package org.joda.time;
017    
018    import java.io.IOException;
019    import java.io.ObjectInputStream;
020    import java.io.ObjectOutputStream;
021    import java.io.Serializable;
022    import java.util.Locale;
023    
024    import org.joda.time.base.BaseDateTime;
025    import org.joda.time.chrono.ISOChronology;
026    import org.joda.time.field.AbstractReadableInstantFieldProperty;
027    import org.joda.time.field.FieldUtils;
028    import org.joda.time.format.ISODateTimeFormat;
029    
030    /**
031     * MutableDateTime is the standard implementation of a modifiable datetime class.
032     * It holds the datetime as milliseconds from the Java epoch of 1970-01-01T00:00:00Z.
033     * <p>
034     * This class uses a Chronology internally. The Chronology determines how the
035     * millisecond instant value is converted into the date time fields.
036     * The default Chronology is <code>ISOChronology</code> which is the agreed
037     * international standard and compatable with the modern Gregorian calendar.
038     * <p>
039     * Each individual field can be accessed in two ways:
040     * <ul>
041     * <li><code>getHourOfDay()</code>
042     * <li><code>hourOfDay().get()</code>
043     * </ul>
044     * The second technique also provides access to other useful methods on the
045     * field:
046     * <ul>
047     * <li>get numeric value
048     * <li>set numeric value
049     * <li>add to numeric value
050     * <li>add to numeric value wrapping with the field
051     * <li>get text vlaue
052     * <li>get short text value
053     * <li>set text value
054     * <li>field maximum value
055     * <li>field minimum value
056     * </ul>
057     *
058     * <p>
059     * MutableDateTime is mutable and not thread-safe, unless concurrent threads
060     * are not invoking mutator methods.
061     *
062     * @author Guy Allard
063     * @author Brian S O'Neill
064     * @author Stephen Colebourne
065     * @author Mike Schrag
066     * @since 1.0
067     * @see DateTime
068     */
069    public class MutableDateTime
070            extends BaseDateTime
071            implements ReadWritableDateTime, Cloneable, Serializable {
072    
073        /** Serialization version */
074        private static final long serialVersionUID = 2852608688135209575L;
075    
076        /** Rounding is disabled */
077        public static final int ROUND_NONE = 0;
078        /** Rounding mode as described by {@link DateTimeField#roundFloor} */
079        public static final int ROUND_FLOOR = 1;
080        /** Rounding mode as described by {@link DateTimeField#roundCeiling} */
081        public static final int ROUND_CEILING = 2;
082        /** Rounding mode as described by {@link DateTimeField#roundHalfFloor} */
083        public static final int ROUND_HALF_FLOOR = 3;
084        /** Rounding mode as described by {@link DateTimeField#roundHalfCeiling} */
085        public static final int ROUND_HALF_CEILING = 4;
086        /** Rounding mode as described by {@link DateTimeField#roundHalfEven} */
087        public static final int ROUND_HALF_EVEN = 5;
088    
089        /** The field to round on */
090        private DateTimeField iRoundingField;
091        /** The mode of rounding */
092        private int iRoundingMode;
093    
094        //-----------------------------------------------------------------------
095        /**
096         * Constructs an instance set to the current system millisecond time
097         * using <code>ISOChronology</code> in the default time zone.
098         */
099        public MutableDateTime() {
100            super();
101        }
102    
103        /**
104         * Constructs an instance set to the current system millisecond time
105         * using <code>ISOChronology</code> in the specified time zone.
106         * <p>
107         * If the specified time zone is null, the default zone is used.
108         *
109         * @param zone  the time zone, null means default zone
110         */
111        public MutableDateTime(DateTimeZone zone) {
112            super(zone);
113        }
114    
115        /**
116         * Constructs an instance set to the current system millisecond time
117         * using the specified chronology.
118         * <p>
119         * If the chronology is null, <code>ISOChronology</code>
120         * in the default time zone is used.
121         *
122         * @param chronology  the chronology, null means ISOChronology in default zone
123         */
124        public MutableDateTime(Chronology chronology) {
125            super(chronology);
126        }
127    
128        //-----------------------------------------------------------------------
129        /**
130         * Constructs an instance set to the milliseconds from 1970-01-01T00:00:00Z
131         * using <code>ISOChronology</code> in the default time zone.
132         *
133         * @param instant  the milliseconds from 1970-01-01T00:00:00Z
134         */
135        public MutableDateTime(long instant) {
136            super(instant);
137        }
138    
139        /**
140         * Constructs an instance set to the milliseconds from 1970-01-01T00:00:00Z
141         * using <code>ISOChronology</code> in the specified time zone.
142         * <p>
143         * If the specified time zone is null, the default zone is used.
144         *
145         * @param instant  the milliseconds from 1970-01-01T00:00:00Z
146         * @param zone  the time zone, null means default zone
147         */
148        public MutableDateTime(long instant, DateTimeZone zone) {
149            super(instant, zone);
150        }
151    
152        /**
153         * Constructs an instance set to the milliseconds from 1970-01-01T00:00:00Z
154         * using the specified chronology.
155         * <p>
156         * If the chronology is null, <code>ISOChronology</code>
157         * in the default time zone is used.
158         *
159         * @param instant  the milliseconds from 1970-01-01T00:00:00Z
160         * @param chronology  the chronology, null means ISOChronology in default zone
161         */
162        public MutableDateTime(long instant, Chronology chronology) {
163            super(instant, chronology);
164        }
165    
166        //-----------------------------------------------------------------------
167        /**
168         * Constructs an instance from an Object that represents a datetime.
169         * <p>
170         * If the object implies a chronology (such as GregorianCalendar does),
171         * then that chronology will be used. Otherwise, ISO default is used.
172         * Thus if a GregorianCalendar is passed in, the chronology used will
173         * be GJ, but if a Date is passed in the chronology will be ISO.
174         * <p>
175         * The recognised object types are defined in
176         * {@link org.joda.time.convert.ConverterManager ConverterManager} and
177         * include ReadableInstant, String, Calendar and Date.
178         *
179         * @param instant  the datetime object, null means now
180         * @throws IllegalArgumentException if the instant is invalid
181         */
182        public MutableDateTime(Object instant) {
183            super(instant, (Chronology) null);
184        }
185    
186        /**
187         * Constructs an instance from an Object that represents a datetime,
188         * forcing the time zone to that specified.
189         * <p>
190         * If the object implies a chronology (such as GregorianCalendar does),
191         * then that chronology will be used, but with the time zone adjusted.
192         * Otherwise, ISO is used in the specified time zone.
193         * If the specified time zone is null, the default zone is used.
194         * Thus if a GregorianCalendar is passed in, the chronology used will
195         * be GJ, but if a Date is passed in the chronology will be ISO.
196         * <p>
197         * The recognised object types are defined in
198         * {@link org.joda.time.convert.ConverterManager ConverterManager} and
199         * include ReadableInstant, String, Calendar and Date.
200         *
201         * @param instant  the datetime object, null means now
202         * @param zone  the time zone, null means default time zone
203         * @throws IllegalArgumentException if the instant is invalid
204         */
205        public MutableDateTime(Object instant, DateTimeZone zone) {
206            super(instant, zone);
207        }
208    
209        /**
210         * Constructs an instance from an Object that represents a datetime,
211         * using the specified chronology.
212         * <p>
213         * If the chronology is null, ISO in the default time zone is used.
214         * Any chronology implied by the object (such as GregorianCalendar does)
215         * is ignored.
216         * <p>
217         * The recognised object types are defined in
218         * {@link org.joda.time.convert.ConverterManager ConverterManager} and
219         * include ReadableInstant, String, Calendar and Date.
220         *
221         * @param instant  the datetime object, null means now
222         * @param chronology  the chronology, null means ISOChronology in default zone
223         * @throws IllegalArgumentException if the instant is invalid
224         */
225        public MutableDateTime(Object instant, Chronology chronology) {
226            super(instant, DateTimeUtils.getChronology(chronology));
227        }
228    
229        //-----------------------------------------------------------------------
230        /**
231         * Constructs an instance from datetime field values
232         * using <code>ISOChronology</code> in the default time zone.
233         *
234         * @param year  the year
235         * @param monthOfYear  the month of the year
236         * @param dayOfMonth  the day of the month
237         * @param hourOfDay  the hour of the day
238         * @param minuteOfHour  the minute of the hour
239         * @param secondOfMinute  the second of the minute
240         * @param millisOfSecond  the millisecond of the second
241         */
242        public MutableDateTime(
243                int year,
244                int monthOfYear,
245                int dayOfMonth,
246                int hourOfDay,
247                int minuteOfHour,
248                int secondOfMinute,
249                int millisOfSecond) {
250            super(year, monthOfYear, dayOfMonth, hourOfDay, minuteOfHour, secondOfMinute, millisOfSecond);
251        }
252    
253        /**
254         * Constructs an instance from datetime field values
255         * using <code>ISOChronology</code> in the specified time zone.
256         * <p>
257         * If the specified time zone is null, the default zone is used.
258         *
259         * @param year  the year
260         * @param monthOfYear  the month of the year
261         * @param dayOfMonth  the day of the month
262         * @param hourOfDay  the hour of the day
263         * @param minuteOfHour  the minute of the hour
264         * @param secondOfMinute  the second of the minute
265         * @param millisOfSecond  the millisecond of the second
266         * @param zone  the time zone, null means default time zone
267         */
268        public MutableDateTime(
269                int year,
270                int monthOfYear,
271                int dayOfMonth,
272                int hourOfDay,
273                int minuteOfHour,
274                int secondOfMinute,
275                int millisOfSecond,
276                DateTimeZone zone) {
277            super(year, monthOfYear, dayOfMonth,
278                  hourOfDay, minuteOfHour, secondOfMinute, millisOfSecond, zone);
279        }
280    
281        /**
282         * Constructs an instance from datetime field values
283         * using the specified chronology.
284         * <p>
285         * If the chronology is null, <code>ISOChronology</code>
286         * in the default time zone is used.
287         *
288         * @param year  the year
289         * @param monthOfYear  the month of the year
290         * @param dayOfMonth  the day of the month
291         * @param hourOfDay  the hour of the day
292         * @param minuteOfHour  the minute of the hour
293         * @param secondOfMinute  the second of the minute
294         * @param millisOfSecond  the millisecond of the second
295         * @param chronology  the chronology, null means ISOChronology in default zone
296         */
297        public MutableDateTime(
298                int year,
299                int monthOfYear,
300                int dayOfMonth,
301                int hourOfDay,
302                int minuteOfHour,
303                int secondOfMinute,
304                int millisOfSecond,
305                Chronology chronology) {
306            super(year, monthOfYear, dayOfMonth,
307                  hourOfDay, minuteOfHour, secondOfMinute, millisOfSecond, chronology);
308        }
309    
310        //-----------------------------------------------------------------------
311        /**
312         * Gets the field used for rounding this instant, returning null if rounding
313         * is not enabled.
314         * 
315         * @return the rounding field
316         */
317        public DateTimeField getRoundingField() {
318            return iRoundingField;
319        }
320    
321        /**
322         * Gets the rounding mode for this instant, returning ROUND_NONE if rounding
323         * is not enabled.
324         * 
325         * @return the rounding mode constant
326         */
327        public int getRoundingMode() {
328            return iRoundingMode;
329        }
330    
331        /**
332         * Sets the status of rounding to use the specified field and ROUND_FLOOR mode.
333         * A null field will disable rounding.
334         * Once set, the instant is then rounded using the new field and mode.
335         * <p>
336         * Enabling rounding will cause all subsequent calls to {@link #setMillis(long)}
337         * to be rounded. This can be used to control the precision of the instant,
338         * for example by setting a rounding field of minuteOfDay, the seconds and
339         * milliseconds will always be zero.
340         *
341         * @param field rounding field or null to disable
342         */
343        public void setRounding(DateTimeField field) {
344            setRounding(field, MutableDateTime.ROUND_FLOOR);
345        }
346    
347        /**
348         * Sets the status of rounding to use the specified field and mode.
349         * A null field or mode of ROUND_NONE will disable rounding.
350         * Once set, the instant is then rounded using the new field and mode.
351         * <p>
352         * Enabling rounding will cause all subsequent calls to {@link #setMillis(long)}
353         * to be rounded. This can be used to control the precision of the instant,
354         * for example by setting a rounding field of minuteOfDay, the seconds and
355         * milliseconds will always be zero.
356         *
357         * @param field  rounding field or null to disable
358         * @param mode  rounding mode or ROUND_NONE to disable
359         * @throws IllegalArgumentException if mode is unknown, no exception if field is null
360         */
361        public void setRounding(DateTimeField field, int mode) {
362            if (field != null && (mode < ROUND_NONE || mode > ROUND_HALF_EVEN)) {
363                throw new IllegalArgumentException("Illegal rounding mode: " + mode);
364            }
365            iRoundingField = (mode == ROUND_NONE ? null : field);
366            iRoundingMode = (field == null ? ROUND_NONE : mode);
367            setMillis(getMillis());
368        }
369    
370        //-----------------------------------------------------------------------
371        /**
372         * Set the milliseconds of the datetime.
373         * <p>
374         * All changes to the millisecond field occurs via this method.
375         *
376         * @param instant  the milliseconds since 1970-01-01T00:00:00Z to set the
377         * datetime to
378         */
379        public void setMillis(long instant) {
380            switch (iRoundingMode) {
381                case ROUND_NONE:
382                    break;
383                case ROUND_FLOOR:
384                    instant = iRoundingField.roundFloor(instant);
385                    break;
386                case ROUND_CEILING:
387                    instant = iRoundingField.roundCeiling(instant);
388                    break;
389                case ROUND_HALF_FLOOR:
390                    instant = iRoundingField.roundHalfFloor(instant);
391                    break;
392                case ROUND_HALF_CEILING:
393                    instant = iRoundingField.roundHalfCeiling(instant);
394                    break;
395                case ROUND_HALF_EVEN:
396                    instant = iRoundingField.roundHalfEven(instant);
397                    break;
398            }
399    
400            super.setMillis(instant);
401        }
402    
403        /**
404         * Sets the millisecond instant of this instant from another.
405         * <p>
406         * This method does not change the chronology of this instant, just the
407         * millisecond instant.
408         * 
409         * @param instant  the instant to use, null means now
410         */
411        public void setMillis(ReadableInstant instant) {
412            long instantMillis = DateTimeUtils.getInstantMillis(instant);
413            setMillis(instantMillis);  // set via this class not super
414        }
415    
416        //-----------------------------------------------------------------------
417        /**
418         * Add an amount of time to the datetime.
419         * 
420         * @param duration  the millis to add
421         * @throws ArithmeticException if the result exceeds the capacity of the instant
422         */
423        public void add(long duration) {
424            setMillis(FieldUtils.safeAdd(getMillis(), duration));  // set via this class not super
425        }
426    
427        /**
428         * Adds a duration to this instant.
429         * <p>
430         * This will typically change the value of most fields.
431         *
432         * @param duration  the duration to add, null means add zero
433         * @throws ArithmeticException if the result exceeds the capacity of the instant
434         */
435        public void add(ReadableDuration duration) {
436            add(duration, 1);
437        }
438    
439        /**
440         * Adds a duration to this instant specifying how many times to add.
441         * <p>
442         * This will typically change the value of most fields.
443         *
444         * @param duration  the duration to add, null means add zero
445         * @param scalar  direction and amount to add, which may be negative
446         * @throws ArithmeticException if the result exceeds the capacity of the instant
447         */
448        public void add(ReadableDuration duration, int scalar) {
449            if (duration != null) {
450                add(FieldUtils.safeMultiply(duration.getMillis(), scalar));
451            }
452        }
453    
454        /**
455         * Adds a period to this instant.
456         * <p>
457         * This will typically change the value of most fields.
458         *
459         * @param period  the period to add, null means add zero
460         * @throws ArithmeticException if the result exceeds the capacity of the instant
461         */
462        public void add(ReadablePeriod period) {
463            add(period, 1);
464        }
465    
466        /**
467         * Adds a period to this instant specifying how many times to add.
468         * <p>
469         * This will typically change the value of most fields.
470         *
471         * @param period  the period to add, null means add zero
472         * @param scalar  direction and amount to add, which may be negative
473         * @throws ArithmeticException if the result exceeds the capacity of the instant
474         */
475        public void add(ReadablePeriod period, int scalar) {
476            if (period != null) {
477                setMillis(getChronology().add(period, getMillis(), scalar));  // set via this class not super
478            }
479        }
480    
481        //-----------------------------------------------------------------------
482        /**
483         * Set the chronology of the datetime.
484         * <p>
485         * All changes to the chronology occur via this method.
486         * 
487         * @param chronology  the chronology to use, null means ISOChronology in default zone
488         */
489        public void setChronology(Chronology chronology) {
490            super.setChronology(chronology);
491        }
492    
493        //-----------------------------------------------------------------------
494        /**
495         * Sets the time zone of the datetime, changing the chronology and field values.
496         * <p>
497         * Changing the zone using this method retains the millisecond instant.
498         * The millisecond instant is adjusted in the new zone to compensate.
499         * 
500         * chronology. Setting the time zone does not affect the millisecond value
501         * of this instant.
502         * <p>
503         * If the chronology already has this time zone, no change occurs.
504         *
505         * @param newZone  the time zone to use, null means default zone
506         * @see #setZoneRetainFields
507         */
508        public void setZone(DateTimeZone newZone) {
509            newZone = DateTimeUtils.getZone(newZone);
510            Chronology chrono = getChronology();
511            if (chrono.getZone() != newZone) {
512                setChronology(chrono.withZone(newZone));  // set via this class not super
513            }
514        }
515    
516        /**
517         * Sets the time zone of the datetime, changing the chronology and millisecond.
518         * <p>
519         * Changing the zone using this method retains the field values.
520         * The millisecond instant is adjusted in the new zone to compensate.
521         * <p>
522         * If the chronology already has this time zone, no change occurs.
523         *
524         * @param newZone  the time zone to use, null means default zone
525         * @see #setZone
526         */
527        public void setZoneRetainFields(DateTimeZone newZone) {
528            newZone = DateTimeUtils.getZone(newZone);
529            DateTimeZone originalZone = DateTimeUtils.getZone(getZone());
530            if (newZone == originalZone) {
531                return;
532            }
533            
534            long millis = originalZone.getMillisKeepLocal(newZone, getMillis());
535            setChronology(getChronology().withZone(newZone));  // set via this class not super
536            setMillis(millis);
537        }
538    
539        //-----------------------------------------------------------------------
540        /**
541         * Sets the value of one of the fields of the instant, such as hourOfDay.
542         *
543         * @param type  a field type, usually obtained from DateTimeFieldType, not null
544         * @param value  the value to set the field to
545         * @throws IllegalArgumentException if the value is null or invalid
546         */
547        public void set(DateTimeFieldType type, int value) {
548            if (type == null) {
549                throw new IllegalArgumentException("Field must not be null");
550            }
551            setMillis(type.getField(getChronology()).set(getMillis(), value));
552        }
553    
554        /**
555         * Adds to the instant specifying the duration and multiple to add.
556         *
557         * @param type  a field type, usually obtained from DateTimeFieldType, not null
558         * @param amount  the amount to add of this duration
559         * @throws IllegalArgumentException if the value is null or invalid
560         * @throws ArithmeticException if the result exceeds the capacity of the instant
561         */
562        public void add(DurationFieldType type, int amount) {
563            if (type == null) {
564                throw new IllegalArgumentException("Field must not be null");
565            }
566            setMillis(type.getField(getChronology()).add(getMillis(), amount));
567        }
568    
569        //-----------------------------------------------------------------------
570        /**
571         * Set the year to the specified value.
572         *
573         * @param year  the year
574         * @throws IllegalArgumentException if the value is invalid
575         */
576        public void setYear(final int year) {
577            setMillis(getChronology().year().set(getMillis(), year));
578        }
579    
580        /**
581         * Add a number of years to the date.
582         *
583         * @param years  the years to add
584         * @throws IllegalArgumentException if the value is invalid
585         */
586        public void addYears(final int years) {
587            setMillis(getChronology().years().add(getMillis(), years));
588        }
589    
590        //-----------------------------------------------------------------------
591        /**
592         * Set the weekyear to the specified value.
593         *
594         * @param weekyear  the weekyear
595         * @throws IllegalArgumentException if the value is invalid
596         */
597        public void setWeekyear(final int weekyear) {
598            setMillis(getChronology().weekyear().set(getMillis(), weekyear));
599        }
600    
601        /**
602         * Add a number of weekyears to the date.
603         *
604         * @param weekyears  the weekyears to add
605         * @throws IllegalArgumentException if the value is invalid
606         */
607        public void addWeekyears(final int weekyears) {
608            setMillis(getChronology().weekyears().add(getMillis(), weekyears));
609        }
610    
611        //-----------------------------------------------------------------------
612        /**
613         * Set the month of the year to the specified value.
614         *
615         * @param monthOfYear  the month of the year
616         * @throws IllegalArgumentException if the value is invalid
617         */
618        public void setMonthOfYear(final int monthOfYear) {
619            setMillis(getChronology().monthOfYear().set(getMillis(), monthOfYear));
620        }
621    
622        /**
623         * Add a number of months to the date.
624         *
625         * @param months  the months to add
626         * @throws IllegalArgumentException if the value is invalid
627         */
628        public void addMonths(final int months) {
629            setMillis(getChronology().months().add(getMillis(), months));
630        }
631    
632        //-----------------------------------------------------------------------
633        /**
634         * Set the week of weekyear to the specified value.
635         *
636         * @param weekOfWeekyear the week of the weekyear
637         * @throws IllegalArgumentException if the value is invalid
638         */
639        public void setWeekOfWeekyear(final int weekOfWeekyear) {
640            setMillis(getChronology().weekOfWeekyear().set(getMillis(), weekOfWeekyear));
641        }
642    
643        /**
644         * Add a number of weeks to the date.
645         *
646         * @param weeks  the weeks to add
647         * @throws IllegalArgumentException if the value is invalid
648         */
649        public void addWeeks(final int weeks) {
650            setMillis(getChronology().weeks().add(getMillis(), weeks));
651        }
652    
653        //-----------------------------------------------------------------------
654        /**
655         * Set the day of year to the specified value.
656         *
657         * @param dayOfYear the day of the year
658         * @throws IllegalArgumentException if the value is invalid
659         */
660        public void setDayOfYear(final int dayOfYear) {
661            setMillis(getChronology().dayOfYear().set(getMillis(), dayOfYear));
662        }
663    
664        /**
665         * Set the day of the month to the specified value.
666         *
667         * @param dayOfMonth  the day of the month
668         * @throws IllegalArgumentException if the value is invalid
669         */
670        public void setDayOfMonth(final int dayOfMonth) {
671            setMillis(getChronology().dayOfMonth().set(getMillis(), dayOfMonth));
672        }
673    
674        /**
675         * Set the day of week to the specified value.
676         *
677         * @param dayOfWeek  the day of the week
678         * @throws IllegalArgumentException if the value is invalid
679         */
680        public void setDayOfWeek(final int dayOfWeek) {
681            setMillis(getChronology().dayOfWeek().set(getMillis(), dayOfWeek));
682        }
683    
684        /**
685         * Add a number of days to the date.
686         *
687         * @param days  the days to add
688         * @throws IllegalArgumentException if the value is invalid
689         */
690        public void addDays(final int days) {
691            setMillis(getChronology().days().add(getMillis(), days));
692        }
693    
694        //-----------------------------------------------------------------------
695        /**
696         * Set the hour of the day to the specified value.
697         *
698         * @param hourOfDay  the hour of day
699         * @throws IllegalArgumentException if the value is invalid
700         */
701        public void setHourOfDay(final int hourOfDay) {
702            setMillis(getChronology().hourOfDay().set(getMillis(), hourOfDay));
703        }
704    
705        /**
706         * Add a number of hours to the date.
707         *
708         * @param hours  the hours to add
709         * @throws IllegalArgumentException if the value is invalid
710         */
711        public void addHours(final int hours) {
712            setMillis(getChronology().hours().add(getMillis(), hours));
713        }
714        
715        //-----------------------------------------------------------------------
716        /**
717         * Set the minute of the day to the specified value.
718         *
719         * @param minuteOfDay  the minute of day
720         * @throws IllegalArgumentException if the value is invalid
721         */
722        public void setMinuteOfDay(final int minuteOfDay) {
723            setMillis(getChronology().minuteOfDay().set(getMillis(), minuteOfDay));
724        }
725    
726        /**
727         * Set the minute of the hour to the specified value.
728         *
729         * @param minuteOfHour  the minute of hour
730         * @throws IllegalArgumentException if the value is invalid
731         */
732        public void setMinuteOfHour(final int minuteOfHour) {
733            setMillis(getChronology().minuteOfHour().set(getMillis(), minuteOfHour));
734        }
735    
736        /**
737         * Add a number of minutes to the date.
738         *
739         * @param minutes  the minutes to add
740         * @throws IllegalArgumentException if the value is invalid
741         */
742        public void addMinutes(final int minutes) {
743            setMillis(getChronology().minutes().add(getMillis(), minutes));
744        }
745    
746        //-----------------------------------------------------------------------
747        /**
748         * Set the second of the day to the specified value.
749         *
750         * @param secondOfDay  the second of day
751         * @throws IllegalArgumentException if the value is invalid
752         */
753        public void setSecondOfDay(final int secondOfDay) {
754            setMillis(getChronology().secondOfDay().set(getMillis(), secondOfDay));
755        }
756    
757        /**
758         * Set the second of the minute to the specified value.
759         *
760         * @param secondOfMinute  the second of minute
761         * @throws IllegalArgumentException if the value is invalid
762         */
763        public void setSecondOfMinute(final int secondOfMinute) {
764            setMillis(getChronology().secondOfMinute().set(getMillis(), secondOfMinute));
765        }
766    
767        /**
768         * Add a number of seconds to the date.
769         *
770         * @param seconds  the seconds to add
771         * @throws IllegalArgumentException if the value is invalid
772         */
773        public void addSeconds(final int seconds) {
774            setMillis(getChronology().seconds().add(getMillis(), seconds));
775        }
776    
777        //-----------------------------------------------------------------------
778        /**
779         * Set the millis of the day to the specified value.
780         *
781         * @param millisOfDay  the millis of day
782         * @throws IllegalArgumentException if the value is invalid
783         */
784        public void setMillisOfDay(final int millisOfDay) {
785            setMillis(getChronology().millisOfDay().set(getMillis(), millisOfDay));
786        }
787    
788        /**
789         * Set the millis of the second to the specified value.
790         *
791         * @param millisOfSecond  the millis of second
792         * @throws IllegalArgumentException if the value is invalid
793         */
794        public void setMillisOfSecond(final int millisOfSecond) {
795            setMillis(getChronology().millisOfSecond().set(getMillis(), millisOfSecond));
796        }
797    
798        /**
799         * Add a number of milliseconds to the date. The implementation of this
800         * method differs from the {@link #add(long)} method in that a
801         * DateTimeField performs the addition.
802         *
803         * @param millis  the milliseconds to add
804         * @throws IllegalArgumentException if the value is invalid
805         */
806        public void addMillis(final int millis) {
807            setMillis(getChronology().millis().add(getMillis(), millis));
808        }
809    
810        //-----------------------------------------------------------------------
811        /**
812         * Set the date from milliseconds.
813         * The time part of this object will be unaffected.
814         *
815         * @param instant  an instant to copy the date from, time part ignored
816         * @throws IllegalArgumentException if the value is invalid
817         */
818        public void setDate(final long instant) {
819            setMillis(getChronology().millisOfDay().set(instant, getMillisOfDay()));
820        }
821    
822        /**
823         * Set the date from another instant.
824         * The time part of this object will be unaffected.
825         *
826         * @param instant  an instant to copy the date from, time part ignored
827         * @throws IllegalArgumentException if the object is invalid
828         */
829        public void setDate(final ReadableInstant instant) {
830            long instantMillis = DateTimeUtils.getInstantMillis(instant);
831            Chronology instantChrono = DateTimeUtils.getInstantChronology(instant);
832            DateTimeZone zone = instantChrono.getZone();
833            if (zone != null) {
834                instantMillis = zone.getMillisKeepLocal(DateTimeZone.UTC, instantMillis);
835            }
836            setDate(instantMillis);
837        }
838    
839        /**
840         * Set the date from fields.
841         * The time part of this object will be unaffected.
842         *
843         * @param year  the year
844         * @param monthOfYear  the month of the year
845         * @param dayOfMonth  the day of the month
846         * @throws IllegalArgumentException if the value is invalid
847         */
848        public void setDate(
849                final int year,
850                final int monthOfYear,
851                final int dayOfMonth) {
852            Chronology c = getChronology();
853            long instantMidnight = c.getDateTimeMillis(year, monthOfYear, dayOfMonth, 0);
854            setDate(instantMidnight);
855        }
856    
857        //-----------------------------------------------------------------------
858        /**
859         * Set the time from milliseconds.
860         * The date part of this object will be unaffected.
861         *
862         * @param millis  an instant to copy the time from, date part ignored
863         * @throws IllegalArgumentException if the value is invalid
864         */
865        public void setTime(final long millis) {
866            int millisOfDay = ISOChronology.getInstanceUTC().millisOfDay().get(millis);
867            setMillis(getChronology().millisOfDay().set(getMillis(), millisOfDay));
868        }
869    
870        /**
871         * Set the time from another instant.
872         * The date part of this object will be unaffected.
873         *
874         * @param instant  an instant to copy the time from, date part ignored
875         * @throws IllegalArgumentException if the object is invalid
876         */
877        public void setTime(final ReadableInstant instant) {
878            long instantMillis = DateTimeUtils.getInstantMillis(instant);
879            Chronology instantChrono = DateTimeUtils.getInstantChronology(instant);
880            DateTimeZone zone = instantChrono.getZone();
881            if (zone != null) {
882                instantMillis = zone.getMillisKeepLocal(DateTimeZone.UTC, instantMillis);
883            }
884            setTime(instantMillis);
885        }
886    
887        /**
888         * Set the time from fields.
889         * The date part of this object will be unaffected.
890         *
891         * @param hour  the hour
892         * @param minuteOfHour  the minute of the hour
893         * @param secondOfMinute  the second of the minute
894         * @param millisOfSecond  the millisecond of the second
895         * @throws IllegalArgumentException if the value is invalid
896         */
897        public void setTime(
898                final int hour,
899                final int minuteOfHour,
900                final int secondOfMinute,
901                final int millisOfSecond) {
902            long instant = getChronology().getDateTimeMillis(
903                getMillis(), hour, minuteOfHour, secondOfMinute, millisOfSecond);
904            setMillis(instant);
905        }
906    
907        /**
908         * Set the date and time from fields.
909         *
910         * @param year  the year
911         * @param monthOfYear  the month of the year
912         * @param dayOfMonth  the day of the month
913         * @param hourOfDay  the hour of the day
914         * @param minuteOfHour  the minute of the hour
915         * @param secondOfMinute  the second of the minute
916         * @param millisOfSecond  the millisecond of the second
917         * @throws IllegalArgumentException if the value is invalid
918         */
919        public void setDateTime(
920                final int year,
921                final int monthOfYear,
922                final int dayOfMonth,
923                final int hourOfDay,
924                final int minuteOfHour,
925                final int secondOfMinute,
926                final int millisOfSecond) {
927            long instant = getChronology().getDateTimeMillis(
928                year, monthOfYear, dayOfMonth, hourOfDay, minuteOfHour, secondOfMinute, millisOfSecond);
929            setMillis(instant);
930        }
931    
932        //-----------------------------------------------------------------------
933        /**
934         * Gets the property object for the specified type, which contains many useful methods.
935         *
936         * @param type  the field type to get the chronology for
937         * @return the property object
938         * @throws IllegalArgumentException if the field is null or unsupported
939         * @since 1.2
940         */
941        public Property property(DateTimeFieldType type) {
942            if (type == null) {
943                throw new IllegalArgumentException("The DateTimeFieldType must not be null");
944            }
945            DateTimeField field = type.getField(getChronology());
946            if (field.isSupported() == false) {
947                throw new IllegalArgumentException("Field '" + type + "' is not supported");
948            }
949            return new Property(this, field);
950        }
951    
952        /**
953         * Get the era property.
954         * 
955         * @return the era property
956         */
957        public Property era() {
958            return new Property(this, getChronology().era());
959        }
960    
961        /**
962         * Get the century of era property.
963         * 
964         * @return the year of era property
965         */
966        public Property centuryOfEra() {
967            return new Property(this, getChronology().centuryOfEra());
968        }
969    
970        /**
971         * Get the year of century property.
972         * 
973         * @return the year of era property
974         */
975        public Property yearOfCentury() {
976            return new Property(this, getChronology().yearOfCentury());
977        }
978    
979        /**
980         * Get the year of era property.
981         * 
982         * @return the year of era property
983         */
984        public Property yearOfEra() {
985            return new Property(this, getChronology().yearOfEra());
986        }
987    
988        /**
989         * Get the year property.
990         * 
991         * @return the year property
992         */
993        public Property year() {
994            return new Property(this, getChronology().year());
995        }
996    
997        /**
998         * Get the year of a week based year property.
999         * 
1000         * @return the year of a week based year property
1001         */
1002        public Property weekyear() {
1003            return new Property(this, getChronology().weekyear());
1004        }
1005    
1006        /**
1007         * Get the month of year property.
1008         * 
1009         * @return the month of year property
1010         */
1011        public Property monthOfYear() {
1012            return new Property(this, getChronology().monthOfYear());
1013        }
1014    
1015        /**
1016         * Get the week of a week based year property.
1017         * 
1018         * @return the week of a week based year property
1019         */
1020        public Property weekOfWeekyear() {
1021            return new Property(this, getChronology().weekOfWeekyear());
1022        }
1023    
1024        /**
1025         * Get the day of year property.
1026         * 
1027         * @return the day of year property
1028         */
1029        public Property dayOfYear() {
1030            return new Property(this, getChronology().dayOfYear());
1031        }
1032    
1033        /**
1034         * Get the day of month property.
1035         * <p>
1036         * The values for day of month are defined in {@link DateTimeConstants}.
1037         * 
1038         * @return the day of month property
1039         */
1040        public Property dayOfMonth() {
1041            return new Property(this, getChronology().dayOfMonth());
1042        }
1043    
1044        /**
1045         * Get the day of week property.
1046         * <p>
1047         * The values for day of week are defined in {@link DateTimeConstants}.
1048         * 
1049         * @return the day of week property
1050         */
1051        public Property dayOfWeek() {
1052            return new Property(this, getChronology().dayOfWeek());
1053        }
1054    
1055        //-----------------------------------------------------------------------
1056        /**
1057         * Get the hour of day field property
1058         * 
1059         * @return the hour of day property
1060         */
1061        public Property hourOfDay() {
1062            return new Property(this, getChronology().hourOfDay());
1063        }
1064    
1065        /**
1066         * Get the minute of day property
1067         * 
1068         * @return the minute of day property
1069         */
1070        public Property minuteOfDay() {
1071            return new Property(this, getChronology().minuteOfDay());
1072        }
1073    
1074        /**
1075         * Get the minute of hour field property
1076         * 
1077         * @return the minute of hour property
1078         */
1079        public Property minuteOfHour() {
1080            return new Property(this, getChronology().minuteOfHour());
1081        }
1082    
1083        /**
1084         * Get the second of day property
1085         * 
1086         * @return the second of day property
1087         */
1088        public Property secondOfDay() {
1089            return new Property(this, getChronology().secondOfDay());
1090        }
1091    
1092        /**
1093         * Get the second of minute field property
1094         * 
1095         * @return the second of minute property
1096         */
1097        public Property secondOfMinute() {
1098            return new Property(this, getChronology().secondOfMinute());
1099        }
1100    
1101        /**
1102         * Get the millis of day property
1103         * 
1104         * @return the millis of day property
1105         */
1106        public Property millisOfDay() {
1107            return new Property(this, getChronology().millisOfDay());
1108        }
1109    
1110        /**
1111         * Get the millis of second property
1112         * 
1113         * @return the millis of second property
1114         */
1115        public Property millisOfSecond() {
1116            return new Property(this, getChronology().millisOfSecond());
1117        }
1118    
1119        //-----------------------------------------------------------------------
1120        /**
1121         * Clone this object without having to cast the returned object.
1122         *
1123         * @return a clone of the this object.
1124         */
1125        public MutableDateTime copy() {
1126            return (MutableDateTime) clone();
1127        }
1128    
1129        //-----------------------------------------------------------------------
1130        /**
1131         * Clone this object.
1132         *
1133         * @return a clone of this object.
1134         */
1135        public Object clone() {
1136            try {
1137                return super.clone();
1138            } catch (CloneNotSupportedException ex) {
1139                throw new InternalError("Clone error");
1140            }
1141        }
1142    
1143        /**
1144         * Output the date time in ISO8601 format (yyyy-MM-ddTHH:mm:ss.SSSZZ).
1145         * 
1146         * @return ISO8601 time formatted string.
1147         */
1148        public String toString() {
1149            return ISODateTimeFormat.dateTime().print(this);
1150        }
1151    
1152        /**
1153         * MutableDateTime.Property binds a MutableDateTime to a
1154         * DateTimeField allowing powerful datetime functionality to be easily
1155         * accessed.
1156         * <p>
1157         * The example below shows how to use the property to change the value of a
1158         * MutableDateTime object.
1159         * <pre>
1160         * MutableDateTime dt = new MutableDateTime(1972, 12, 3, 13, 32, 19, 123);
1161         * dt.year().add(20);
1162         * dt.second().roundFloor().minute().set(10);
1163         * </pre>
1164         * <p>
1165         * MutableDateTime.Propery itself is thread-safe and immutable, but the
1166         * MutableDateTime being operated on is not.
1167         *
1168         * @author Stephen Colebourne
1169         * @author Brian S O'Neill
1170         * @since 1.0
1171         */
1172        public static final class Property extends AbstractReadableInstantFieldProperty {
1173            
1174            /** Serialization version */
1175            private static final long serialVersionUID = -4481126543819298617L;
1176            
1177            /** The instant this property is working against */
1178            private MutableDateTime iInstant;
1179            /** The field this property is working against */
1180            private DateTimeField iField;
1181            
1182            /**
1183             * Constructor.
1184             * 
1185             * @param instant  the instant to set
1186             * @param field  the field to use
1187             */
1188            Property(MutableDateTime instant, DateTimeField field) {
1189                super();
1190                iInstant = instant;
1191                iField = field;
1192            }
1193            
1194            /**
1195             * Writes the property in a safe serialization format.
1196             */
1197            private void writeObject(ObjectOutputStream oos) throws IOException {
1198                oos.writeObject(iInstant);
1199                oos.writeObject(iField.getType());
1200            }
1201    
1202            /**
1203             * Reads the property from a safe serialization format.
1204             */
1205            private void readObject(ObjectInputStream oos) throws IOException, ClassNotFoundException {
1206                iInstant = (MutableDateTime) oos.readObject();
1207                DateTimeFieldType type = (DateTimeFieldType) oos.readObject();
1208                iField = type.getField(iInstant.getChronology());
1209            }
1210    
1211            //-----------------------------------------------------------------------
1212            /**
1213             * Gets the field being used.
1214             * 
1215             * @return the field
1216             */
1217            public DateTimeField getField() {
1218                return iField;
1219            }
1220            
1221            /**
1222             * Gets the milliseconds of the datetime that this property is linked to.
1223             * 
1224             * @return the milliseconds
1225             */
1226            protected long getMillis() {
1227                return iInstant.getMillis();
1228            }
1229            
1230            /**
1231             * Gets the chronology of the datetime that this property is linked to.
1232             * 
1233             * @return the chronology
1234             * @since 1.4
1235             */
1236            protected Chronology getChronology() {
1237                return iInstant.getChronology();
1238            }
1239            
1240            /**
1241             * Gets the mutable datetime being used.
1242             * 
1243             * @return the mutable datetime
1244             */
1245            public MutableDateTime getMutableDateTime() {
1246                return iInstant;
1247            }
1248            
1249            //-----------------------------------------------------------------------
1250            /**
1251             * Adds a value to the millis value.
1252             * 
1253             * @param value  the value to add
1254             * @return the mutable datetime being used, so calls can be chained
1255             * @see DateTimeField#add(long,int)
1256             */
1257            public MutableDateTime add(int value) {
1258                iInstant.setMillis(getField().add(iInstant.getMillis(), value));
1259                return iInstant;
1260            }
1261            
1262            /**
1263             * Adds a value to the millis value.
1264             * 
1265             * @param value  the value to add
1266             * @return the mutable datetime being used, so calls can be chained
1267             * @see DateTimeField#add(long,long)
1268             */
1269            public MutableDateTime add(long value) {
1270                iInstant.setMillis(getField().add(iInstant.getMillis(), value));
1271                return iInstant;
1272            }
1273            
1274            /**
1275             * Adds a value, possibly wrapped, to the millis value.
1276             * 
1277             * @param value  the value to add
1278             * @return the mutable datetime being used, so calls can be chained
1279             * @see DateTimeField#addWrapField
1280             */
1281            public MutableDateTime addWrapField(int value) {
1282                iInstant.setMillis(getField().addWrapField(iInstant.getMillis(), value));
1283                return iInstant;
1284            }
1285            
1286            //-----------------------------------------------------------------------
1287            /**
1288             * Sets a value.
1289             * 
1290             * @param value  the value to set.
1291             * @return the mutable datetime being used, so calls can be chained
1292             * @see DateTimeField#set(long,int)
1293             */
1294            public MutableDateTime set(int value) {
1295                iInstant.setMillis(getField().set(iInstant.getMillis(), value));
1296                return iInstant;
1297            }
1298            
1299            /**
1300             * Sets a text value.
1301             * 
1302             * @param text  the text value to set
1303             * @param locale  optional locale to use for selecting a text symbol
1304             * @return the mutable datetime being used, so calls can be chained
1305             * @throws IllegalArgumentException if the text value isn't valid
1306             * @see DateTimeField#set(long,java.lang.String,java.util.Locale)
1307             */
1308            public MutableDateTime set(String text, Locale locale) {
1309                iInstant.setMillis(getField().set(iInstant.getMillis(), text, locale));
1310                return iInstant;
1311            }
1312            
1313            /**
1314             * Sets a text value.
1315             * 
1316             * @param text  the text value to set
1317             * @return the mutable datetime being used, so calls can be chained
1318             * @throws IllegalArgumentException if the text value isn't valid
1319             * @see DateTimeField#set(long,java.lang.String)
1320             */
1321            public MutableDateTime set(String text) {
1322                set(text, null);
1323                return iInstant;
1324            }
1325            
1326            //-----------------------------------------------------------------------
1327            /**
1328             * Round to the lowest whole unit of this field.
1329             *
1330             * @return the mutable datetime being used, so calls can be chained
1331             * @see DateTimeField#roundFloor
1332             */
1333            public MutableDateTime roundFloor() {
1334                iInstant.setMillis(getField().roundFloor(iInstant.getMillis()));
1335                return iInstant;
1336            }
1337    
1338            /**
1339             * Round to the highest whole unit of this field.
1340             *
1341             * @return the mutable datetime being used, so calls can be chained
1342             * @see DateTimeField#roundCeiling
1343             */
1344            public MutableDateTime roundCeiling() {
1345                iInstant.setMillis(getField().roundCeiling(iInstant.getMillis()));
1346                return iInstant;
1347            }
1348            
1349            /**
1350             * Round to the nearest whole unit of this field, favoring the floor if
1351             * halfway.
1352             *
1353             * @return the mutable datetime being used, so calls can be chained
1354             * @see DateTimeField#roundHalfFloor
1355             */
1356            public MutableDateTime roundHalfFloor() {
1357                iInstant.setMillis(getField().roundHalfFloor(iInstant.getMillis()));
1358                return iInstant;
1359            }
1360            
1361            /**
1362             * Round to the nearest whole unit of this field, favoring the ceiling if
1363             * halfway.
1364             *
1365             * @return the mutable datetime being used, so calls can be chained
1366             * @see DateTimeField#roundHalfCeiling
1367             */
1368            public MutableDateTime roundHalfCeiling() {
1369                iInstant.setMillis(getField().roundHalfCeiling(iInstant.getMillis()));
1370                return iInstant;
1371            }
1372    
1373            /**
1374             * Round to the nearest whole unit of this field. If halfway, the ceiling
1375             * is favored over the floor only if it makes this field's value even.
1376             *
1377             * @return the mutable datetime being used, so calls can be chained
1378             * @see DateTimeField#roundHalfEven
1379             */
1380            public MutableDateTime roundHalfEven() {
1381                iInstant.setMillis(getField().roundHalfEven(iInstant.getMillis()));
1382                return iInstant;
1383            }
1384        }
1385    
1386    }